1   /*
2    * Copyright (C) 2007 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.collect;
18  
19  import static com.google.common.base.Preconditions.checkPositionIndexes;
20  
21  import com.google.common.annotations.GwtCompatible;
22  
23  import java.util.Collection;
24  
25  import javax.annotation.Nullable;
26  
27  /**
28   * Static utility methods pertaining to object arrays.
29   *
30   * @author Kevin Bourrillion
31   * @since 2.0 (imported from Google Collections Library)
32   */
33  @GwtCompatible(emulated = true)
34  public final class ObjectArrays {
35    static final Object[] EMPTY_ARRAY = new Object[0];
36  
37    private ObjectArrays() {}
38  
39    /**
40     * Returns a new array of the given length with the same type as a reference
41     * array.
42     *
43     * @param reference any array of the desired type
44     * @param length the length of the new array
45     */
46    public static <T> T[] newArray(T[] reference, int length) {
47      return Platform.newArray(reference, length);
48    }
49  
50    /**
51     * Returns a new array that prepends {@code element} to {@code array}.
52     *
53     * @param element the element to prepend to the front of {@code array}
54     * @param array the array of elements to append
55     * @return an array whose size is one larger than {@code array}, with
56     *     {@code element} occupying the first position, and the
57     *     elements of {@code array} occupying the remaining elements.
58     */
59    public static <T> T[] concat(@Nullable T element, T[] array) {
60      T[] result = newArray(array, array.length + 1);
61      result[0] = element;
62      System.arraycopy(array, 0, result, 1, array.length);
63      return result;
64    }
65  
66    /**
67     * Returns a new array that appends {@code element} to {@code array}.
68     *
69     * @param array the array of elements to prepend
70     * @param element the element to append to the end
71     * @return an array whose size is one larger than {@code array}, with
72     *     the same contents as {@code array}, plus {@code element} occupying the
73     *     last position.
74     */
75    public static <T> T[] concat(T[] array, @Nullable T element) {
76      T[] result = arraysCopyOf(array, array.length + 1);
77      result[array.length] = element;
78      return result;
79    }
80  
81    /** GWT safe version of Arrays.copyOf. */
82    static <T> T[] arraysCopyOf(T[] original, int newLength) {
83      T[] copy = newArray(original, newLength);
84      System.arraycopy(
85          original, 0, copy, 0, Math.min(original.length, newLength));
86      return copy;
87    }
88  
89    /**
90     * Returns an array containing all of the elements in the specified
91     * collection; the runtime type of the returned array is that of the specified
92     * array. If the collection fits in the specified array, it is returned
93     * therein. Otherwise, a new array is allocated with the runtime type of the
94     * specified array and the size of the specified collection.
95     *
96     * <p>If the collection fits in the specified array with room to spare (i.e.,
97     * the array has more elements than the collection), the element in the array
98     * immediately following the end of the collection is set to {@code null}.
99     * This is useful in determining the length of the collection <i>only</i> if
100    * the caller knows that the collection does not contain any null elements.
101    *
102    * <p>This method returns the elements in the order they are returned by the
103    * collection's iterator.
104    *
105    * <p>TODO(kevinb): support concurrently modified collections?
106    *
107    * @param c the collection for which to return an array of elements
108    * @param array the array in which to place the collection elements
109    * @throws ArrayStoreException if the runtime type of the specified array is
110    *     not a supertype of the runtime type of every element in the specified
111    *     collection
112    */
113   static <T> T[] toArrayImpl(Collection<?> c, T[] array) {
114     int size = c.size();
115     if (array.length < size) {
116       array = newArray(array, size);
117     }
118     fillArray(c, array);
119     if (array.length > size) {
120       array[size] = null;
121     }
122     return array;
123   }
124   
125   /**
126    * Implementation of {@link Collection#toArray(Object[])} for collections backed by an object
127    * array. the runtime type of the returned array is that of the specified array. If the collection
128    * fits in the specified array, it is returned therein. Otherwise, a new array is allocated with
129    * the runtime type of the specified array and the size of the specified collection.
130    *
131    * <p>If the collection fits in the specified array with room to spare (i.e., the array has more
132    * elements than the collection), the element in the array immediately following the end of the
133    * collection is set to {@code null}. This is useful in determining the length of the collection
134    * <i>only</i> if the caller knows that the collection does not contain any null elements.
135    */
136   static <T> T[] toArrayImpl(Object[] src, int offset, int len, T[] dst) {
137     checkPositionIndexes(offset, offset + len, src.length);
138     if (dst.length < len) {
139       dst = newArray(dst, len);
140     } else if (dst.length > len) {
141       dst[len] = null;
142     }
143     System.arraycopy(src, offset, dst, 0, len);
144     return dst;
145   }
146 
147   /**
148    * Returns an array containing all of the elements in the specified
149    * collection. This method returns the elements in the order they are returned
150    * by the collection's iterator. The returned array is "safe" in that no
151    * references to it are maintained by the collection. The caller is thus free
152    * to modify the returned array.
153    *
154    * <p>This method assumes that the collection size doesn't change while the
155    * method is running.
156    *
157    * <p>TODO(kevinb): support concurrently modified collections?
158    *
159    * @param c the collection for which to return an array of elements
160    */
161   static Object[] toArrayImpl(Collection<?> c) {
162     return fillArray(c, new Object[c.size()]);
163   }
164 
165   /**
166    * Returns a copy of the specified subrange of the specified array that is literally an Object[],
167    * and not e.g. a {@code String[]}.
168    */
169   static Object[] copyAsObjectArray(Object[] elements, int offset, int length) {
170     checkPositionIndexes(offset, offset + length, elements.length);
171     if (length == 0) {
172       return EMPTY_ARRAY;
173     }
174     Object[] result = new Object[length];
175     System.arraycopy(elements, offset, result, 0, length);
176     return result;
177   }
178 
179   private static Object[] fillArray(Iterable<?> elements, Object[] array) {
180     int i = 0;
181     for (Object element : elements) {
182       array[i++] = element;
183     }
184     return array;
185   }
186 
187   /**
188    * Swaps {@code array[i]} with {@code array[j]}.
189    */
190   static void swap(Object[] array, int i, int j) {
191     Object temp = array[i];
192     array[i] = array[j];
193     array[j] = temp;
194   }
195 
196   static Object[] checkElementsNotNull(Object... array) {
197     return checkElementsNotNull(array, array.length);
198   }
199   
200   static Object[] checkElementsNotNull(Object[] array, int length) {
201     for (int i = 0; i < length; i++) {
202       checkElementNotNull(array[i], i);
203     }
204     return array;
205   }
206 
207   // We do this instead of Preconditions.checkNotNull to save boxing and array
208   // creation cost.
209   static Object checkElementNotNull(Object element, int index) {
210     if (element == null) {
211       throw new NullPointerException("at index " + index);
212     }
213     return element;
214   }
215 }
216